package MultiThreaded;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.swing.JLabel;

public class CalculusThread  implements Runnable{
	
	String CallPutFlag; // Call or put?
	Double S; // current price 
	Double X; // Strike price of the option
	Double T; // Time to maturity of the option (in years)
	Double r; // Discount rate (risk-free interest rate)
	Double b; //cost of carry rate (cost of interest, dividends and any other additional costs)
	Double v; // volatility of the underlying asset
	int nSteps; // Number of steps to execute for each option
	int nSimulations; // Number of simulations to run
	Double result;
	JLabel resultat;;
	
	public Double getResult() {
		return result;
	}



	public CalculusThread(String callPutFlag, Double s, Double x, Double t,
			Double r, Double b, Double v, int nSteps, int nSimulations, JLabel resultat) {
		super();
		CallPutFlag = callPutFlag;
		S = s;
		X = x;
		T = t;
		this.r = r;
		this.b = b;
		this.v = v;
		this.nSteps = nSteps;
		this.nSimulations = nSimulations;
		this.resultat=resultat;
	}



	@Override
	public void run() {

		//partition of the calculation in a pool of callable threads
		final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.9;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    //final int poolSize=1200;
	    
	    final List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
	    
		
		Double Dt, St, Drift, vSqrdt;
		Double Sum=0.0;
		int i, j, z=0;
		
		Dt= T/nSteps;
		Drift = (b - (v*v) / 2) * Dt;
		vSqrdt = v * java.lang.Math.sqrt(Dt);
		
		
		if(CallPutFlag.equals("c")) {
			z=1;
		}
		else if (CallPutFlag.equals("p")) {
			z=-1;
		}
	    
	    	    for(i=0; i<nSimulations; i++) {
	    	    	St=S;
	    	    	Callable<Double> c= new LoopCallable(nSteps,St, Drift, vSqrdt,  z, X, Sum);
	    	    	partitions.add(c);
	    	        } 
	    	    
	   final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    
		List<Future<Double>> resultsimulations = null;
		try {
			resultsimulations = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	   
	for(final Future<Double> resultofasimulation : resultsimulations)
		try {
			Sum += resultofasimulation.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 

	    executorPool.shutdown();
	    	    

	    		result=java.lang.Math.exp(-r*T) * (Sum / nSimulations);
	    		System.out.println("result=" + result);
	    		resultat.setText("premium="+result);
	    		
	    	      
	}
		
		
}


